import numeric from '../plugins/numeric/numeric-wrapper.js';

// 图像处理核心类
export class ImageProcessor {
    constructor() {
        this.maxSize = 4000;
    }

    // 计算单应性矩阵
    computeHomography(srcPoints, dstPoints) {
        if (!Array.isArray(srcPoints) || !Array.isArray(dstPoints) || 
            srcPoints.length !== 4 || dstPoints.length !== 4) {
            throw new Error('源点和目标点必须各为4个点的数组');
        }
        
        const A = [];
        for (let i = 0; i < 4; i++) {
            const [x, y] = srcPoints[i];
            const [u, v] = dstPoints[i];
            A.push([x, y, 1, 0, 0, 0, -u*x, -u*y]);
            A.push([0, 0, 0, x, y, 1, -v*x, -v*y]);
        }
        
        const b = [];
        for (let i = 0; i < 4; i++) {
            const [u, v] = dstPoints[i];
            b.push(u);
            b.push(v);
        }

        try {
            const h = numeric.solve(A, b);
            return [
                [h[0], h[1], h[2]],
                [h[3], h[4], h[5]],
                [h[6], h[7], 1]
            ];
        } catch (error) {
            throw new Error('无法计算单应性矩阵：' + error.message);
        }
    }

    // 计算输出尺寸
    calculateOutputSize(points, originalWidth, originalHeight, displayWidth, displayHeight) {
        const scaleX = originalWidth / displayWidth;
        const scaleY = originalHeight / displayHeight;
        
        const originalPoints = points.map(p => ({
            x: p.x * scaleX,
            y: p.y * scaleY
        }));
        
        const topWidth = this.distance(originalPoints[0], originalPoints[1]);
        const bottomWidth = this.distance(originalPoints[3], originalPoints[2]);
        const leftHeight = this.distance(originalPoints[0], originalPoints[3]);
        const rightHeight = this.distance(originalPoints[1], originalPoints[2]);

        const width = Math.round((topWidth + bottomWidth) / 2);
        const height = Math.round((leftHeight + rightHeight) / 2);

        const maxSize = this.maxSize;
        if (width > maxSize || height > maxSize) {
            const ratio = Math.min(maxSize / width, maxSize / height);
            return {
                width: Math.round(width * ratio),
                height: Math.round(height * ratio)
            };
        }

        return { width, height };
    }

    // 执行图像矫正
    correctImage(srcPoints, dstPoints, originalImage, outputWidth, outputHeight) {
        if (!originalImage || !originalImage.width || !originalImage.height) {
            throw new Error('无效的输入图像');
        }

        const H = this.computeHomography(srcPoints, dstPoints);
        const H_inv = numeric.inv(H);

        // 创建临时 canvas 处理原始图片
        const tempCanvas = document.createElement('canvas');
        tempCanvas.width = originalImage.width;
        tempCanvas.height = originalImage.height;
        const tempCtx = tempCanvas.getContext('2d');
        tempCtx.drawImage(originalImage, 0, 0);
        const originalData = tempCtx.getImageData(0, 0, originalImage.width, originalImage.height).data;

        // 创建输出图像数据
        const outputCanvas = document.createElement('canvas');
        outputCanvas.width = outputWidth;
        outputCanvas.height = outputHeight;
        const outputCtx = outputCanvas.getContext('2d');
        const outputImageData = outputCtx.createImageData(outputWidth, outputHeight);
        const outputData = outputImageData.data;

        // 执行像素映射
        for (let y = 0; y < outputHeight; y++) {
            for (let x = 0; x < outputWidth; x++) {
                const dstPt = [x, y, 1];
                const srcPt = this.multiplyMatrixVector(H_inv, dstPt);
                const srcX = srcPt[0] / srcPt[2];
                const srcY = srcPt[1] / srcPt[2];

                const color = this.bilinearInterpolate(
                    originalData, 
                    originalImage.width, 
                    originalImage.height, 
                    srcX, 
                    srcY
                );

                const index = (y * outputWidth + x) * 4;
                outputData[index] = color.r;
                outputData[index + 1] = color.g;
                outputData[index + 2] = color.b;
                outputData[index + 3] = color.a;
            }
        }

        outputCtx.putImageData(outputImageData, 0, 0);
        return outputCanvas;
    }

    // 辅助方法
    distance(p1, p2) {
        const dx = p2.x - p1.x;
        const dy = p2.y - p1.y;
        return Math.sqrt(dx * dx + dy * dy);
    }

    multiplyMatrixVector(matrix, vector) {
        const result = [];
        for (let i = 0; i < matrix.length; i++) {
            let sum = 0;
            for (let j = 0; j < vector.length; j++) {
                sum += matrix[i][j] * vector[j];
            }
            result.push(sum);
        }
        return result;
    }

    bilinearInterpolate(data, width, height, x, y) {
        if (x < 0) x = 0;
        if (y < 0) y = 0;
        if (x >= width - 1) x = width - 1.001;
        if (y >= height - 1) y = height - 1.001;

        const x1 = Math.floor(x);
        const y1 = Math.floor(y);
        const x2 = Math.ceil(x);
        const y2 = Math.ceil(y);

        const dx = x - x1;
        const dy = y - y1;

        const q11 = this.getPixel(data, width, height, x1, y1);
        const q21 = this.getPixel(data, width, height, x2, y1);
        const q12 = this.getPixel(data, width, height, x1, y2);
        const q22 = this.getPixel(data, width, height, x2, y2);

        return {
            r: Math.round(this.bilinear(q11.r, q21.r, q12.r, q22.r, dx, dy)),
            g: Math.round(this.bilinear(q11.g, q21.g, q12.g, q22.g, dx, dy)),
            b: Math.round(this.bilinear(q11.b, q21.b, q12.b, q22.b, dx, dy)),
            a: Math.round(this.bilinear(q11.a, q21.a, q12.a, q22.a, dx, dy))
        };
    }

    bilinear(q11, q21, q12, q22, dx, dy) {
        return q11 * (1 - dx) * (1 - dy) +
               q21 * dx * (1 - dy) +
               q12 * (1 - dx) * dy +
               q22 * dx * dy;
    }

    getPixel(data, width, height, x, y) {
        const index = (y * width + x) * 4;
        return {
            r: data[index],
            g: data[index + 1],
            b: data[index + 2],
            a: data[index + 3]
        };
    }
} 